import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import Model.HighScores;
import Model.LocalScore;
import Model.Score;
import org.w3c.dom.*;

import java.io.File;
import java.rmi.Naming;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Created by andreas on 19.10.2014.
 */
public class HighScore {
    private String localFileName = "resources/xml/LocalScores.xml";
    private String serverAddress = "//127.0.0.1/HighScore";

    public HighScore(){
    }

    /**
     * Abrufen der lokalen Ergebnisse
     * @return Die lokalen Ergebnisse
     */
    public LocalScore getLocalScores(){
        LocalScore localScore = new LocalScore();
        Document document = getXMLDocument(localFileName);

        Node root = (Node) document;

        NodeList nodeList = root.getChildNodes().item(0).getChildNodes();
        for (int i = 0; i < nodeList.getLength(); i++) {
            root = nodeList.item(i);

            if (root.getNodeName().equals("LastScore")){
                localScore.LastScore = root.getFirstChild().getNodeValue();
            }
            else if (root.getNodeName().equals("BestScore")){
                localScore.BestScore = root.getFirstChild().getNodeValue();
            }
        }

        return localScore;
    }

    /**
     * Speichern der lokalen Scores
     * @param intScore Das erreichte Ergebnis
     */
    public void setLocalScores(int intScore){
        String score = Integer.toString(intScore);

        LocalScore localScore = getLocalScores();

        Document document = getNewXMLDocument();

        Element localScoresRoot = document.createElement("LocalScores");
        document.appendChild(localScoresRoot);

        Element lastScoreElement = document.createElement("LastScore");
        Text lSValue = document.createTextNode(score);
        lastScoreElement.appendChild(lSValue);
        localScoresRoot.appendChild(lastScoreElement);

        Element bestScoreElement = document.createElement("BestScore");
        if (Integer.parseInt(score) > Integer.parseInt(localScore.BestScore)){
            bestScoreElement.appendChild(document.createTextNode(score));
        }
        else{
            bestScoreElement.appendChild(document.createTextNode(localScore.BestScore));
        }
        localScoresRoot.appendChild(bestScoreElement);

        writeXMLDocument(document);
    }

    /**
     * Abrufen der Online Ergebnisse
     * @return Die Online Ergebnisse
     */
    public HighScores getOnlineScores(){
        HighScores highScore = new HighScores();
        Document document = null;
        try{
            HighScoreInterface server = (HighScoreInterface) Naming.lookup(serverAddress);
            document = server.GetXML();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        Node root = (Node) document;

        if (root != null && root.hasChildNodes() && root.getChildNodes().item(0) != null && root.getChildNodes().item(0).hasChildNodes()){
            NodeList nodeList = root.getChildNodes().item(0).getChildNodes();

            for(int i = 0; i < nodeList.getLength(); i++){
                root = nodeList.item(i);

                NodeList scoreList = root.getChildNodes();
                Score newScore = new Score();

                for(int a = 0; a < scoreList.getLength(); a++) {
                    Node score = scoreList.item(a);

                    if (score.getNodeName().equals("Name")){
                        newScore.Name = score.getFirstChild().getNodeValue();
                    }
                    else if (score.getNodeName().equals("Value")){
                        newScore.Value = score.getFirstChild().getNodeValue();
                    }
                }
                highScore.Scores.add(newScore);
            }
        }

        return highScore;
    }

    /**
     * Speichern der Online Ergebnisse
     * @param name Der Name des Spielers
     * @param intScore Das erreichte Ergebnis
     */
    public void setOnlineScores(String name, int intScore){
        String value = Integer.toString(intScore);

        HighScores highScores = getOnlineScores();

        highScores.Scores.add(new Score(name, value));

        Collections.sort(highScores.Scores, Collections.reverseOrder());
        highScores.Scores = highScores.Scores.subList(0, 10 > highScores.Scores.size() ? highScores.Scores.size() : 10);

        Document document = getNewXMLDocument();

        Element highScoresRoot = document.createElement("HighScores");
        document.appendChild(highScoresRoot);

        for (Score score : highScores.Scores){
            if (score != null && score.Name != null && score.Value != null){
                Element scoreElement = document.createElement("Score");
                Element nameElement = document.createElement("Name");
                nameElement.appendChild(document.createTextNode(score.Name));
                scoreElement.appendChild(nameElement);

                Element valueElement = document.createElement("Value");
                valueElement.appendChild(document.createTextNode(score.Value));
                scoreElement.appendChild(valueElement);
                highScoresRoot.appendChild(scoreElement);
            }
        }

        boolean success = false;
        try{
            HighScoreInterface server = (HighScoreInterface) Naming.lookup(serverAddress);
            success = server.SaveXML(document);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Mit dieser Methode wird ein neues XML Dokument erstellt
     * @return Ein neues Dokument
     */
    private Document getNewXMLDocument(){
        Document document = null;

        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();

            document = builder.newDocument();
            //document.setXmlStandalone(true);
        } catch (Exception e) {
        }

        return document;
    }

    /**
     * Mit dieser Methode wird ein XML Dokument vom übergebenen Pfad abgerufen
     * @param xmlFileName Der Pfad zum Dokument
     * @return Das Dokument
     */
    private Document getXMLDocument(String xmlFileName) {
        Document document = null;

        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            document = builder.parse(new File(xmlFileName));
        } catch (Exception e1) {
        }

        return document;
    }

    /**
     * Das übergebene XML Dokument wird mit dieser Methode an den globalen Pfad des lokalen High Score gespeichert
     * @param document Das zu speichernde Dokument
     */
    private void writeXMLDocument(Document document) {
        File file = new File(localFileName);

        try {

            TransformerFactory transFactory = TransformerFactory.newInstance();
            Transformer transformer = transFactory.newTransformer();

            Source source = new DOMSource(document);
            Result result = new StreamResult(file);

            transformer.transform(source, result);

        } catch (Exception e1) {
        }
    }
}